using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Abp.Domain.Entities;
using Abp.Domain.Entities.Auditing;
using Abp.Domain.Repositories;
using Abp.Orm;
using Abp.Specifications;
using Yozeev.BusinessLogic;
using Yozeev.Common.Extensions;
using Yozeev.Common.Query;
using Yozeev.SystemConfig;

namespace Yozeev.Common
{
    public class QueryHelper: IQueryHelper
    {
        public Expression<Func<T, bool>> WhereExp<T>(ICollection<QueryData> queryData) where T: class, new()
        {
            T t = new T();
            Expression<Func<T, bool>> whereExp = entity => 1 == 1;
            if (queryData == null || queryData.Count == 0)
            {
                return whereExp;
            }
            Expression where = null;
            ParameterExpression par = Expression.Parameter(typeof(T), "entity");
            foreach (var item in queryData)
            {
                ConstantExpression age = null;
                BinaryExpression expression = null;
                MemberExpression memName = null;
                string[] nvafileId = item.Field.Split('.');
                if (nvafileId.Length == 2)
                {
                    Expression navpro = Expression.Property(par, typeof(T).GetProperty(nvafileId[0]));
                    memName = Expression.Property(navpro, nvafileId[1]);

                }
                else if (nvafileId.Length == 3)
                {
                    var navpro = Expression.Property(par, typeof(T).GetProperty(nvafileId[0]));
                    var navpro1 = Expression.Property(navpro, navpro.Type.GetProperty(nvafileId[1]));
                    memName = Expression.Property(navpro1, nvafileId[2]);

                }
                else
                    memName = Expression.Property(par, item.Field);

                switch (item.Method.ToLower())
                {
                    case ExpressionMethod.Contains:
                        ConstantExpression constExpress =
                            Expression.Constant(item.Value.ConvertToSimpleType(memName.Type), memName.Type);
                        MethodInfo constMethodinfo = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                        MethodCallExpression callConstExpress = Expression.Call(memName, constMethodinfo, constExpress);
                        where = Concat(where, item.Logic, callConstExpress);
                        break;
                    case ExpressionMethod.Start:
                        ConstantExpression startExpress = Expression.Constant(item.Value.ConvertToSimpleType(memName.Type), memName.Type);
                        MethodInfo startMethodinfo = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
                        MethodCallExpression callStartExpress = Expression.Call(memName, startMethodinfo, startExpress);
                        where = Concat(where, item.Logic, callStartExpress);
                        break;
                    case ExpressionMethod.End:

                        ConstantExpression endExpress = Expression.Constant(item.Value.ConvertToSimpleType(memName.Type), memName.Type);
                        MethodInfo endMethodinfo = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
                        MethodCallExpression callEndExpress = Expression.Call(memName, endMethodinfo, endExpress);
                        where = Concat(where, item.Logic, callEndExpress);
                        break;
                    case ExpressionMethod.GreaterThanOrEqual:
                        age = Expression.Constant(item.Value.ConvertToSimpleType(memName.Type), memName.Type);
                        expression = Expression.GreaterThanOrEqual(memName, age);
                        where = Concat(where, item.Logic, expression);
                        break;
                    case ExpressionMethod.LessThanOrEqual:
                        age = Expression.Constant(item.Value.ConvertToSimpleType(memName.Type), memName.Type);
                        expression = Expression.LessThanOrEqual(memName, age);
                        where = Concat(where, item.Logic, expression);
                        break;
                    case ExpressionMethod.Equal:
                        age = Expression.Constant(item.Value.ConvertToSimpleType(memName.Type), memName.Type);
                        expression = Expression.Equal(memName, age);
                        where = Concat(where, item.Logic, expression);
                        break;
                    case ExpressionMethod.LessThan:
                        age = Expression.Constant(item.Value.ConvertToSimpleType(memName.Type), memName.Type);
                        expression = Expression.LessThan(memName, age);
                        where = Concat(where, item.Logic, expression);
                        break;
                    case ExpressionMethod.GreaterThan:
                        age = Expression.Constant(item.Value.ConvertToSimpleType(memName.Type), memName.Type);
                        expression = Expression.GreaterThan(memName, age);
                        where = Concat(where, item.Logic, expression);
                        break;

                    case ExpressionMethod.In:
                        object[] invalues = item.Value.Split(',');
                        if (invalues.Length > 0)
                        {
                            var equals = invalues.Select(v => (Expression)Expression.Equal(memName, Expression.Constant(v.ConvertToSimpleType(memName.Type), memName.Type)));
                            var exp = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));
                            where = Concat(where, item.Logic, exp);
                        }
                        break;
                    case ExpressionMethod.NotIn:
                        object[] notinvalues = item.Value.Split(',');
                        if (notinvalues.Length > 0)
                        {
                            var notequals = notinvalues.Select(v => (Expression)Expression.NotEqual(memName, Expression.Constant(v.ConvertToSimpleType(memName.Type), memName.Type)));
                            var exp = notequals.Aggregate<Expression>((accumulate, notequal) => Expression.AndAlso(accumulate, notequal));
                            where = Concat(where, item.Logic, exp);
                        }
                        break;
                }
            }

            return Expression.Lambda<Func<T, bool>>(where, par);
        }

        public IQueryable<T> GetAllQueryable<T, P>(IRepository<T, P> repository, object dto, string minDatePropPrefix = "MinDate",
            string maxDatePropPrefix = "MaxDate") where T : class, IEntity<P>
        {
            throw new NotImplementedException();
        }

        private static Expression Concat(Expression left, string logic, Expression right)
        {
            if (left == null) return right;
            if (right == null) return left;
            left = IsOr(logic) ? Expression.OrElse(left, right) : Expression.AndAlso(left, right);
            return left;
        }

        private static bool IsOr(string logic)
        {
            return logic == null || logic == "" ? true : logic.ToUpper() == "OR"; 
        }
        /// <summary>
        /// 根据权限类型查询数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="whereExp">原查询条件</param>
        /// <param name="viewType">数据查看类型</param>
        /// <param name="branchUser">机构用户</param>
        /// <returns></returns>
        public Expression<Func<T, bool>> SetWhereExp<T>(Expression<Func<T, bool>> whereExp,ViewTypeEnum viewType,BranchUser branchUser) where T : ByBranchEntity<Guid>
        {
            //非admin账号
            //if (branchUser.User.Name!="admin")
            if (branchUser != null)
            {
                //查询出数据查看类型
                switch (viewType)
                {
                    case ViewTypeEnum.viewown:
                        //仅查看自己的数据
                        whereExp = whereExp.And(m => m.CreatorUserId == branchUser.UserId);
                        break;
                    case ViewTypeEnum.viewownorgan:
                        //仅查看所在机构的数据
                        whereExp = whereExp.And(m => m.BranchId == branchUser.BranchId);
                        break;
                    case ViewTypeEnum.viewsuborgan:
                        //仅查看所在机构的子机构的数据
                        whereExp = whereExp.And(m => m.Branch.ParentId == branchUser.BranchId);
                        break;
                    case ViewTypeEnum.viewallorgan: break;
                }
            }
            else
            {

            }
            return whereExp;
        }
    }
}
